package com.oceantrader.sale.commons.config.api;

import java.util.UUID;

import org.springframework.stereotype.Component;

import com.oceantrader.sale.commons.config.exceptions.ParamException;
import com.oceantrader.sale.commons.config.exceptions.ServiceException;
import com.oceantrader.sale.constant.BackendApiContext;
import com.xuesinuo.xtool.Np;

import io.vertx.core.json.Json;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 后台API的统一处理：/backend/...
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class BackendApiRoot {

    private final Router router;
    private final BackendApiAuth backendApiAuth;
    /**
     * 无需登录的接口
     */
    private static final String[] unsign = { "/backend/staff/signin" };

    @PostConstruct
    public void start() {
        router.route("/backend/*").order(Integer.MIN_VALUE)
                .handler(BodyHandler.create().setBodyLimit(1024 * 1024))// 请求体大小限制
                .handler(http -> {
                    http.response().setChunked(true).putHeader("Content-Type", "application/json");
                    http.next();
                });

        router.route("/backend/*").order(-2)
                .handler(http -> {
                    String authorization = http.request().headers().get("Authorization");
                    if (authorization != null && authorization.startsWith("Bearer ")) {
                        String token = authorization.substring(7);
                        backendApiAuth.check(token)
                                .onSuccess(userId -> {
                                    http.put(BackendApiContext.TOKEN, token);
                                    http.put(BackendApiContext.STAFF_ID, userId);
                                })
                                .onFailure(e -> http.fail(e))
                                .onComplete(a -> http.next());
                    } else {
                        http.next();
                    }
                });

        router.route("/backend/*").order(-1)
                .handler(http -> {
                    String path = http.request().path();
                    if (Np.i(path).notIn(unsign)) {
                        Long staffId = http.get(BackendApiContext.STAFF_ID);
                        String token = http.get(BackendApiContext.TOKEN);
                        if (staffId == null && token == null) {
                            http.fail(new ServiceException("请先登录"));
                        } else if (staffId == null && token != null) {
                            http.fail(new ServiceException("登录已过期，请重新登录"));
                        }
                    }
                    http.next();
                });

        router.route("/backend/*").order(Integer.MAX_VALUE)
                .handler(http -> {
                    http.end();
                });

        router.route("/backend/*").order(Integer.MIN_VALUE)
                .failureHandler(http -> {
                    ApiResult<?> apiResult = new ApiResult<>();
                    Throwable t = http.failure();
                    if (t != null) {
                        if (t instanceof ParamException) {
                            log.warn("[PARAM_ERROR] API => " + http.request().uri() + " \n " + t.getMessage());
                            apiResult.setCode(ApiResultCode.PARAM_ERROR);
                            apiResult.setMessage("Param Exception: " + t.getMessage());
                            http.response().setStatusCode(400).send(Json.encode(apiResult));
                            return;
                        }
                        if (t instanceof ServiceException) {
                            log.warn("[SERVICE_ERROR] API => " + http.request().uri() + " \n " + t.getMessage());
                            apiResult.setCode(ApiResultCode.SERVICE_ERROR);
                            apiResult.setMessage(t.getMessage());
                            http.response().setStatusCode(400).send(Json.encode(apiResult));
                            return;
                        }
                    }
                    String errorId = UUID.randomUUID().toString().substring(0, 8);
                    log.error("api error [" + errorId + "]", t);
                    apiResult.setCode(ApiResultCode.SYSTEM_ERROR);
                    apiResult.setMessage("System error (" + errorId + ").");
                    http.response().setStatusCode(500).send(Json.encode(apiResult));
                    return;
                });
    }
}
